#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>

sem_t except_tabacco, except_paper, except_match, finish;

typedef enum {
    EXCEPT_TABACCO = 0,
    EXCEPT_PAPER,
    EXCEPT_MATCH,
} Ingredient;

void* agent(void* arg) {
    int delay = 0;
    static int rand = 7; // 初始化一个值，伪装成随机数
    printf("agent: start to randomly generate 2 ingredients\n");

    while (1) {
        int ingred = rand % 3;
        // 使用线性同余法更新 rand
        rand = (1664525 * rand + 1013904223) %  0x80000000;
        switch (ingred) {
            case EXCEPT_TABACCO:
                sem_post(&except_tabacco);
                printf("agent: generate paper and match\n");
                break;
            case EXCEPT_PAPER:
                sem_post(&except_paper);
                printf("agent: generate tabacco and match\n");
                break;
            case EXCEPT_MATCH:
                sem_post(&except_match);
                printf("agent: generate paper and tabacco\n");
                break;
            default:
                break;
        }
        printf("agent: waiting for smoker finish...\n");
        sem_wait(&finish); // 等待一个吸烟者完成
    }
}

void* smoker_with_tabacco(void* arg) {
    while (1) {
        // 等待材料
        printf("smoker_with_tabacco  : waiting for paper and match...\n");
        sem_wait(&except_tabacco);
        printf("smoker_with_tabacco  : Got paper and match!\n");
        // 吸烟
        printf("smoker_with_tabacco: smoking......\n");
        int delay = 0xfffffff;
        while (delay--);
        // 完成
        sem_post(&finish);
        printf("smoker_with_tabacco: I am finished\n");
    }
}

void* smoker_with_paper(void* arg) {
    while (1) {
        // 等待材料
        printf("smoker_with_paper  : waiting for tabacco and match...\n");
        sem_wait(&except_paper);
        printf("smoker_with_paper   : Got tabacco and match!\n");
        // 吸烟
        printf("smoker_with_paper: smoking......\n");
        int delay = 0xfffffff;
        while (delay--);
        // 完成
        sem_post(&finish);
        printf("smoker_with_paper: I am finished!\n");
    }
}

void* smoker_with_match(void* arg) {
    while (1) {
        // 等待材料
        printf("smoker_with_match  : waiting for paper and tabacco...\n");
        sem_wait(&except_match);
        printf("smoker_with_match   : Got paper and tabacco!\n");
        // 吸烟
        printf("smoker_with_match: smoking......\n");
        int delay = 0xfffffff;
        while (delay--);
        // 完成
        sem_post(&finish);
        printf("smoker_with_match: I am finished\n");
    }
}

int main() {
    pthread_t t1, t2, t3, t4;

    sem_init(&except_tabacco, 0, 0);
    sem_init(&except_paper, 0, 0);
    sem_init(&except_match, 0, 0);
    sem_init(&finish, 0, 0);

    pthread_create(&t1, NULL, agent, NULL);
    pthread_create(&t2, NULL, smoker_with_tabacco, NULL);
    pthread_create(&t3, NULL, smoker_with_paper, NULL);
    pthread_create(&t4, NULL, smoker_with_match, NULL);

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    pthread_join(t3, NULL);
    pthread_join(t4, NULL);

    return 0;
}
